#ifndef EASYASIO_PROTORPC_RPC_CHANNEL_HPP
#define EASYASIO_PROTORPC_RPC_CHANNEL_HPP

#include <map>
#include <memory>
#include <functional>
#include <string>
#include <atomic>
#include <mutex>

#include <google/protobuf/service.h>

#include "rpc_codec.hpp"
#include "../net/tcp_connection.hpp"

namespace google {
namespace protobuf {

// Defined in other files.
class Descriptor;            // descriptor.h
class ServiceDescriptor;     // descriptor.h
class MethodDescriptor;      // descriptor.h
class Message;               // message.h

class Closure;

class RpcController;
class Service;

}  // namespace protobuf
}  // namespace google


namespace easyasio
{
namespace net
{

class RpcChannel : public ::google::protobuf::RpcChannel
{
public:
    RpcChannel();

    explicit RpcChannel(const TcpConnectionPtr& conn);

    ~RpcChannel();

    void setConnection(const TcpConnectionPtr& conn)
    {
    conn_ = conn;
    }

    void setServices(const std::map<std::string, ::google::protobuf::Service*>* services)
    {
    services_ = services;
    }

    void CallMethod(const ::google::protobuf::MethodDescriptor* method,
                  ::google::protobuf::RpcController* controller,
                  const ::google::protobuf::Message* request,
                  ::google::protobuf::Message* response,
                  ::google::protobuf::Closure* done);

    void onMessage(const TcpConnectionPtr& conn, Buffer* buf);

    private:
    void onRpcMessage(const TcpConnectionPtr& conn, const RpcMessage& message);

    void doneCallback(::google::protobuf::Message* response, int64_t id);

    struct OutstandingCall
    {
    ::google::protobuf::Message* response;
    ::google::protobuf::Closure* done;
    };

    RpcCodec codec_;
    TcpConnectionPtr conn_;
    std::atomic_uint64_t id_;

    std::mutex mutex_;
    std::map<int64_t, OutstandingCall> outstandings_;

    const std::map<std::string, ::google::protobuf::Service*>* services_;
    };
    typedef std::shared_ptr<RpcChannel> RpcChannelPtr;

}
}

#endif  // MUDUO_NET_PROTORPC_RPCCHANNEL_H
